//
//  UIImage+Extends.m
//  shenbian
//
//  Created by MagicYang on 2/26/11.
//  Copyright 2011 personal. All rights reserved.
//

#import "UIImage+Extends.h"
#import <Accelerate/Accelerate.h>
#define SAFECOLOR(color) MIN(255,MAX(0,color))

static int16_t gaussianblur_kernel[25] = {
	1, 4, 6, 4, 1,
	4, 16, 24, 16, 4,
	6, 24, 36, 24, 6,
	4, 16, 24, 16, 4,
	1, 4, 6, 4, 1
};

@implementation UIImage (Resizing)

- (UIImage*)transformWidth:(CGFloat)width height:(CGFloat)height rotate:(BOOL)rotate {
	CGFloat destW = width;
	CGFloat destH = height;
	CGFloat sourceW = width;
	CGFloat sourceH = height;
	if (rotate) {
		if (self.imageOrientation == UIImageOrientationRight
			|| self.imageOrientation == UIImageOrientationLeft) {
			sourceW = height;
			sourceH = width;
		}
	}
	
	CGImageRef imageRef = self.CGImage;
	CGContextRef bitmap = CGBitmapContextCreate(NULL,
												destW,
												destH,
												CGImageGetBitsPerComponent(imageRef),
												0,
												CGImageGetColorSpace(imageRef),
												CGImageGetBitmapInfo(imageRef));
	
	if (rotate) {
		if (self.imageOrientation == UIImageOrientationDown) {
			CGContextTranslateCTM(bitmap, sourceW, sourceH);
			CGContextRotateCTM(bitmap, 180 * (M_PI/180));
		} else if (self.imageOrientation == UIImageOrientationLeft) {
			CGContextTranslateCTM(bitmap, sourceH, 0);
			CGContextRotateCTM(bitmap, 90 * (M_PI/180));
		} else if (self.imageOrientation == UIImageOrientationRight) {
			CGContextTranslateCTM(bitmap, 0, sourceW);
			CGContextRotateCTM(bitmap, -90 * (M_PI/180));
		}
	}
	
	CGContextDrawImage(bitmap, CGRectMake(0,0,sourceW,sourceH), imageRef);
	
	CGImageRef ref = CGBitmapContextCreateImage(bitmap);
	UIImage* result = [UIImage imageWithCGImage:ref];
	CGContextRelease(bitmap);
	CGImageRelease(ref);
	
	return result;
}

+ (UIImage *)imageWithColor:(UIColor *)color
                   withSize:(CGSize)size
{
    UIImage *img = nil;

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];


    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    
    CGContextSetFillColorWithColor(contextRef, color.CGColor);
    CGContextFillRect(contextRef, rect);
    
    img = UIGraphicsGetImageFromCurrentImageContext();
    
    [img retain];
        
    UIGraphicsEndImageContext();
    
    [pool drain];
    
    return [img autorelease];
}


+ (NSArray*) makeKernel:(int)length
{
	NSMutableArray *kernel = [[[NSMutableArray alloc] initWithCapacity:10] autorelease];
	int radius = length / 2;
	
	double m = 1.0f/(2*M_PI*radius*radius);
	double a = 2.0 * radius * radius;
	double sum = 0.0;
	
	for (int y = 0-radius; y < length-radius; y++)
	{
		NSMutableArray *row = [[[NSMutableArray alloc] initWithCapacity:10] autorelease];
        for (int x = 0-radius; x < length-radius; x++)
        {
			double dist = (x*x) + (y*y);
			double val = m*exp(-(dist / a));
			[row addObject:[NSNumber numberWithDouble:val]];
			sum += val;
        }
		[kernel addObject:row];
	}
	
	//for Kernel-Sum of 1.0
	NSMutableArray *finalKernel = [[[NSMutableArray alloc] initWithCapacity:length] autorelease];
	for (int y = 0; y < length; y++)
	{
		NSMutableArray *row = [kernel objectAtIndex:y];
		NSMutableArray *newRow = [[[NSMutableArray alloc] initWithCapacity:length] autorelease];
        for (int x = 0; x < length; x++)
        {
			NSNumber *value = [row objectAtIndex:x];
			[newRow addObject:[NSNumber numberWithDouble:([value doubleValue] / sum)]];
        }
		[finalKernel addObject:newRow];
	}
	return finalKernel;
}


- (UIImage*) applyConvolve:(NSArray*)kernel
{
	CGImageRef inImage = self.CGImage;
	CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
	CFDataRef m_OutDataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
    
	int length = CFDataGetLength(m_DataRef);
	CFMutableDataRef m_DataRefEdit = CFDataCreateMutableCopy(NULL,length,m_DataRef);
    UInt8 * m_PixelBuf = (UInt8 *) CFDataGetMutableBytePtr(m_DataRefEdit);
    
    int outputLength = CFDataGetLength(m_OutDataRef);
	CFMutableDataRef m_OutDataRefEdit = CFDataCreateMutableCopy(NULL,outputLength,m_DataRef);
    CFRelease(m_DataRef);
    CFRelease(m_OutDataRef);
    UInt8 * m_OutPixelBuf = (UInt8 *) CFDataGetMutableBytePtr(m_OutDataRefEdit);
	
	int h = CGImageGetHeight(inImage);
	int w = CGImageGetWidth(inImage);
	
	int kh = [kernel count] / 2;
	int kw = [[kernel objectAtIndex:0] count] / 2;
	int i = 0, j = 0, n = 0, m = 0;

	for (i = 0; i < h; i++) {
		for (j = 0; j < w; j++) {
			int outIndex = (i*w*4) + (j*4);
			double r = 0, g = 0, b = 0;
			for (n = -kh; n <= kh; n++) {
				for (m = -kw; m <= kw; m++) {
					if (i + n >= 0 && i + n < h) {
						if (j + m >= 0 && j + m < w) {
							double f = [[[kernel objectAtIndex:(n + kh)] objectAtIndex:(m + kw)] doubleValue];
							if (f == 0) {continue;}
							int inIndex = ((i+n)*w*4) + ((j+m)*4);
							r += m_PixelBuf[inIndex] * f;
							g += m_PixelBuf[inIndex + 1] * f;
							b += m_PixelBuf[inIndex + 2] * f;
						}
					}
				}
			}
			m_OutPixelBuf[outIndex]     = SAFECOLOR((int)r);
			m_OutPixelBuf[outIndex + 1] = SAFECOLOR((int)g);
			m_OutPixelBuf[outIndex + 2] = SAFECOLOR((int)b);
			m_OutPixelBuf[outIndex + 3] = 255;
		}
	}
	
	CGContextRef ctx = CGBitmapContextCreate(m_OutPixelBuf,
											 CGImageGetWidth(inImage),
											 CGImageGetHeight(inImage),
											 CGImageGetBitsPerComponent(inImage),
											 CGImageGetBytesPerRow(inImage),
											 CGImageGetColorSpace(inImage),
											 CGImageGetBitmapInfo(inImage)
											 );
	
	CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
	CGContextRelease(ctx);
	UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
	CGImageRelease(imageRef);
    CFRelease(m_DataRefEdit);
    CFRelease(m_OutDataRefEdit);
	return finalImage;
	
}


@end
